package com.hdax.dmw.order.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdax.dmw.common.exceptions.OrderException;
import com.hdax.dmw.common.utils.Result;
import com.hdax.dmw.common.utils.ResultGenerator;
import com.hdax.dmw.common.utils.ServiceResultEnum;
import com.hdax.dmw.common.utils.TokenUtil;
import com.hdax.dmw.entity.item.Item;
import com.hdax.dmw.entity.order.Order;
import com.hdax.dmw.entity.order.OrderLinkUser;
import com.hdax.dmw.entity.order.TxMsg;
import com.hdax.dmw.entity.scheduler.SchedulerSeat;
import com.hdax.dmw.entity.user.LinkUser;
import com.hdax.dmw.order.dtos.LinkUserDto;
import com.hdax.dmw.order.dtos.OrderListDto;
import com.hdax.dmw.order.feign.ItemFeign;
import com.hdax.dmw.order.feign.LinkUserFeign;
import com.hdax.dmw.order.feign.SchedulerSeatFeign;
import com.hdax.dmw.order.mapstruct.LinkUserDtoMapper;
import com.hdax.dmw.order.mapstruct.OrderListDtoMapper;
import com.hdax.dmw.order.service.OrderLinkUserService;
import com.hdax.dmw.order.service.OrderService;
import com.hdax.dmw.order.mappers.OrderMapper;
import com.hdax.dmw.order.service.TxMsgService;
import com.hdax.dmw.order.vo.SubmitOrderVo;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author guoyisha
* @description 针对表【dm_order(订单表)】的数据库操作Service实现
* @createDate 2023-07-28 14:30:54
*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
    implements OrderService{

    @Autowired
    private LinkUserFeign linkUserFeign;
    @Autowired
    private ItemFeign itemFeign;
    @Autowired
    private SchedulerSeatFeign seatFeign;
    @Autowired
    private LinkUserDtoMapper linkUserDtoMapper;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderLinkUserService orderLinkUserService;
    @Autowired
    private TxMsgService txMsgService;

    @Override
    public Result<List<LinkUserDto>> linkUserList(Long userId) {
        List<LinkUser> linkUsers = linkUserFeign.linkUserList(userId);
        List<LinkUserDto> dtos = linkUserDtoMapper.toTargetList(linkUsers);
        return ResultGenerator.genSuccessResult(dtos);
    }

    @Override
    public Order detail(String orderNo) {
        return getOne(new QueryWrapper<Order>().eq("orderNo",orderNo));
    }

    @Autowired
    private OrderListDtoMapper orderListDtoMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Override
    public Result<List<OrderListDto>> orderList(Map<String, Object> params) {
        List<Order> orders = baseMapper.getOrders(params);
        return ResultGenerator.genSuccessResult(orderListDtoMapper.toTargetList(orders));
    }

    // dm_order(dm_order,dm_order_link_user)
    // dm_scheduler(dm_scheduler_seat)
    /**
     * 1. 用户是否登录
     * 2. 人/票数量是否一致
     * 3. 座位是否已经被购买
     * 4. 演出商品是否存在
     * 5. 订单联系人必须存在
     * @param vo
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,
    rollbackFor = {OrderException.class})
    public Result<Map<String, String>> submitOrder(SubmitOrderVo vo, String token) {

        //要添加的订单对象
        Order order = new Order();

        //生成订单号 ： 1. 全局唯一（雪花算法） 2. 所有应用共享
        Snowflake snowflake = new Snowflake();
        String orderNo = snowflake.nextIdStr();
        order.setOrderNo(orderNo);
        // 获取请求token并验证
        Map<String,String> tokenMap = new HashMap<>();
        //当前登录用户id
        Long userId = 0L;
        try {
            tokenMap = TokenUtil.parseToken(token);
            userId = Long.parseLong(tokenMap.get("id"));
        }catch (Exception e){
            throw new OrderException(ServiceResultEnum.USER_NULL_ERROR);
        }
        order.setUserId(userId);
        order.setScheduleId(vo.getSchedulerId());
        Long itemId = vo.getItemId();
        //远程调用判断商品是否存在
        Item item = itemFeign.detail(itemId);
        if(ObjectUtil.isNull(item)){
            throw new OrderException(ServiceResultEnum.GOODS_NOT_EXIST);
        }
        order.setItemId(item.getId());
        order.setItemName(item.getItemName());
        order.setOrderType(0);
        //所有联系人
        String[] linkIds = vo.getLinkIds().split(",");
        //所有座位
        String[] seats = vo.getSeatPositions().split(",");
        if(linkIds.length!=seats.length){
            throw new OrderException(ServiceResultEnum.ORDER_ITEM_NULL_ERROR);
        }
        order.setTotalCount(seats.length);

        //计算商品总价
        Integer totalAmount = 0;
        //数组：存储每一个座位价格
        Integer[] prices = new Integer[seats.length];
        //座位集合
        List<SchedulerSeat> schedulerSeats = new ArrayList<>();
        for (int i = 0; i < seats.length; i++) {
            String[] position = seats[i].split("_");
            Integer x = Integer.parseInt(position[0]);
            Integer y = Integer.parseInt(position[1]);
            Long scheduleId =vo.getSchedulerId();
            //每一个座位
            SchedulerSeat seatDetail = seatFeign.detail(scheduleId, x, y);
            if(seatDetail.getOrderNo() != null &&
            seatDetail.getUserId() != null &&
            seatDetail.getStatus() != 1){
                throw new OrderException(ServiceResultEnum.ORDER_ITEM_NULL_ERROR);
            }
            totalAmount+=seatDetail.getPrice();
            prices[i] = seatDetail.getPrice();
            seatDetail.setOrderNo(orderNo);
            seatDetail.setUserId(userId);
            seatDetail.setStatus(2);
            schedulerSeats.add(seatDetail);
        }
        order.setIsNeedInsurance(vo.getIsNeedInsurance());
        order.setIsNeedInvoice(vo.getIsNeedInvoice());
        order.setInvoiceType(vo.getInvoiceType());
        order.setInvoiceHead(vo.getInvoiceHead());
        order.setInvoiceNo(vo.getInvoiceId());
        //是否购买保险
        if (vo.getIsNeedInsurance() == 1) {
            totalAmount += 20;
            order.setInsuranceAmount(20);
        }
        order.setTotalAmount(totalAmount);

        //
        List<OrderLinkUser> orderLinkUsers = new ArrayList<>();

        for (int i = 0; i < linkIds.length; i++) {
            String[] position = seats[i].split("_");
            Integer x = Integer.parseInt(position[0]);
            Integer y = Integer.parseInt(position[1]);
            //
            long linkId = Long.parseLong(linkIds[i]);
            LinkUser linkUser = linkUserFeign.detail(linkId, userId);
            if(ObjectUtil.isNull(linkUser)){
                throw new OrderException(ServiceResultEnum.ORDER_ITEM_NULL_ERROR);
            }
            OrderLinkUser orderLinkUser = new OrderLinkUser();
            orderLinkUser.setOrderId(orderNo);
            orderLinkUser.setLinkUserName(linkUser.getName());
            orderLinkUser.setLinkUserId(linkUser.getId());
            orderLinkUser.setX(x);
            orderLinkUser.setY(y);
            orderLinkUser.setPrice(prices[i]);
            orderLinkUsers.add(orderLinkUser);
        }

        //分布式事务
        //新增dm_order dm_order_link_user
        orderService.save(order);
        orderLinkUserService.saveBatch(orderLinkUsers);

        //记录数据到本地消息表
        LocalDateTime now = LocalDateTime.now();
        TxMsg txMsg = new TxMsg();
        txMsg.setId(orderNo);
        txMsg.setBizType(1);
        txMsg.setAtime(now);
        txMsg.setVersion(1);
        txMsg.setMsgResult(0);
        txMsg.setTryCount(1);

        Map<String,Object> msgMap = new HashMap<>();
        msgMap.put("orderNo",orderNo);
        msgMap.put("atime",now.toInstant(ZoneOffset.of("+8")).toEpochMilli());
        msgMap.put("linkIds",linkIds);
        msgMap.put("seatPositions",seats);
        msgMap.put("userId",userId);
        msgMap.put("scheduleId",vo.getSchedulerId());
        txMsg.setMsg(JSONUtil.toJsonStr(msgMap));
        txMsgService.save(txMsg);
        //向mq投递消息（当前订单已经新增成功）
        //orderNo 1234 --> mq --> 1234成功了啊！！！
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(orderNo);
        //创建交换器dm_order_tx（topic） 路由（tx.order.add） 队列(order_tx_queue)
        rabbitTemplate.convertAndSend("dm_order_tx","tx.order.add",JSONUtil.toJsonStr(txMsg),correlationData);

        //修改  dm_scheduler_seat
        //seatFeign.batchUpdate(schedulerSeats);
        //发送订单编号到mq并记录过期时间
        rabbitTemplate.convertAndSend("dm_order_exchange","dm.order",orderNo,message -> {
            MessageProperties messageProperties = message.getMessageProperties();
            messageProperties.setExpiration("900000");
            messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            return message;
        });

        Map<String,String> result = new HashMap<>();
        result.put("orderNo",orderNo);
        return ResultGenerator.genSuccessResult(result);
    }
}




